/***********************************************************************************************************************
*                                                                                                                      *
* SPLASH build system v0.1                                                                                             *
*                                                                                                                      *
* Copyright (c) 2013 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                                 *
*                                                                                                                      *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                        *
*                                                                                                                      *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                           *
*                                                                                                                      *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                                                      *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                                                      *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                          *
*                                                                                                                      *
***********************************************************************************************************************/

#ifndef Nocgenv2GeneratedSourceNode_h
#define Nocgenv2GeneratedSourceNode_h

#include "VerilogGeneratedSourceNode.h"

class Nocgenv2GeneratedSourceNode;

enum NocgenDeviceFamily
{
	FAMILY_SPARTAN6,
	FAMILY_ARTIX7,
	FAMILY_KINTEX7
};

/**
	@brief A single node in the quadtree
 */
class NocgenQuadtreeNode
{
public:
	NocgenQuadtreeNode(std::string name = "");
	virtual ~NocgenQuadtreeNode();
	
	//Instance name (8 chars or less)
	std::string m_name;

	//The assigned address (or the base if assigned a subnet)
	uint16_t m_baseaddr;
	
	//The number of addresses this node needs
	uint16_t m_subnetsize;
	
	//Child nodes (only valid if we're a /14 or larger)
	NocgenQuadtreeNode* m_children[4];
	
	//Indicates if this node is hooked up to the RPC or DMA networks
	bool m_rpc;
	bool m_dma;
};


#include "NocgenPLL.h"
#include "NocgenNode.h"

/**
	@brief A single pin
 */
class NocgenBSPPin
{
public:
	
	enum pin_direction
	{
		DIR_IN 		= 1,
		DIR_OUT 	= 2,
		DIR_INOUT 	= 3,
		DIR_NC 		= 4
	};
	
	enum termination
	{
		TERM_NONE		= 1,
		TERM_APPROX_25 	= 2,
		TERM_APPROX_50 	= 3,
		TERM_APPROX_75 	= 4
	};
	
	enum pullmodes
	{
		PULL_NONE 	= 1,
		PULL_UP 	= 2,
		PULL_DOWN 	= 3
	};
	
	enum drivemodes
	{
		DRIVE_DEFAULT	= 1,
		DRIVE_FAST 		= 2
	};

	NocgenBSPPin(
		std::string name = "",
		std::string loc = "",
		std::string iostandard = "",
		unsigned int dir = DIR_IN,
		unsigned int pull = PULL_NONE,
		unsigned int drive = DRIVE_DEFAULT,
		unsigned int term = TERM_NONE)
		: m_name(name)
		, m_iostandard(iostandard)
		, m_loc(loc)
		, m_dir(dir)
		, m_pull(pull)
		, m_drive(drive)
		, m_term(term)
	{}

	std::string m_name;
	std::string m_iostandard;
	std::string m_loc;
	unsigned int m_dir;
	unsigned int m_pull;
	unsigned int m_drive;
	unsigned int m_term;
};

class NocgenRouter : public NocgenQuadtreeNode
{
public:
	NocgenRouter(uint16_t baseaddr, uint16_t subnetsize);
	virtual ~NocgenRouter();
};

/**
	@brief Nocgen-created top-level source module
 */
class Nocgenv2GeneratedSourceNode : public VerilogGeneratedSourceNode
{
public:
	Nocgenv2GeneratedSourceNode(BuildGraph* graph, CodeGenScriptNode* src, CodeGenScriptNode* bsp, std::string fname);
	virtual ~Nocgenv2GeneratedSourceNode();

	static Nocgenv2GeneratedSourceNode* CreateNocgenNode(BuildGraph* graph, std::string script, std::string bsp);
		
	virtual std::string GetOutputPath();
	virtual std::string GetDescription();
	virtual std::string GetBinaryPath();
	virtual std::string GetConstraintsPath();
	virtual std::string GetDotPath();
	
	std::string GetNameserverHostPath();
	std::string GetNameserverAddrPath();
	
	std::string GetTopLevel()
	{ return m_toplevel; }
	
	std::string GetDevice()
	{ return m_device; }
	
	std::string GetSelfClockNet()
	{ return m_selfclock; }
	
	NocgenClockNet GetClockNet(std::string str)
	{ return m_clocknets[str]; }
	
	NocgenClockNet GetBSPClockNet(std::string str)
	{ return m_bspclocks[str]; }
	
	bool IsBSPClockNet(std::string str);
	bool IsClockNet(std::string str);
	void AddClockNet(std::string name, NocgenClockNet clk);
	void AddClockNetFromBSP(std::string name);
	void AddPinFromBSP(std::string name, unsigned int dir);
	void AddBusFromBSP(std::string name, unsigned int width, unsigned int dir);
	
	int GetSignalWidth(std::string name);
	
	NocgenDeviceFamily GetDeviceFamily();
	int GetSpeedGrade();
	
	BuildGraph* GetGraph()
	{ return m_graph; }
	
	std::string template_get_contents(std::string fname);
		
	CodeGenScriptNode* GetSourceFile()
	{ return m_srcfile; }
		
protected:
	virtual std::string GetHash();
	virtual void Update(Cluster* cluster);
	virtual void UpdateDependencies();
	
	void ReadLines(std::string fname, std::vector<std::string>& lines);
	void ParseBSP(std::string fname, const std::vector<std::string>& bsplines);
	void ParseScript(std::string fname, const std::vector<std::string>& scriptlines);
	
	void GenerateNetworkTopology();
	void GenerateCode();
	void GenerateRouters();
	void GenerateNameserverTable();
	std::string GenerateNode(NocgenNode* node);
	
	CodeGenScriptNode* m_srcfile;
	CodeGenScriptNode* m_bspfile;
	
	//Our target device
	std::string m_device;
	
	//The pins in the BSP
	std::map<std::string, NocgenBSPPin> m_bsppins;
	
	//List of buses by width
	std::map<std::string, int> m_buswidths;
	
	//The clocks in the BSP
	std::map<std::string, NocgenClockNet> m_bspclocks;
	
	//Our top-level module name
	std::string m_toplevel;
	
	//The entities in the design
	std::vector<NocgenPLL*> m_plls;
	std::vector<NocgenNode*> m_nodes;
	
	//The pins actually used in this design
	std::map<std::string, NocgenBSPPin> m_toppins;
	
	//The clock nets in this design
	std::map<std::string, NocgenClockNet> m_clocknets;
	
	//List of cross-clock constraints
	std::vector< std::pair<std::string, std::string> > m_crossclocks;
	
	//List of nets to ignore in timing analysis
	std::vector<std::string> m_tigs;
	
	//List of GTP clocks
	std::vector<std::string> m_gtpclocks;
	
	//List of constant assignments
	std::map<std::string, bool> m_constants;
	
	//Generated code
	std::string m_code;
	std::string m_constraints;
	std::string m_dotcode;
	
	//Name of the internal clock, or empty if not used
	std::string m_selfclock;
	
	//The root of the router tree
	NocgenRouter* m_rootRouter;
	
	//The name server and system info nodes
	NocgenNode* m_namesrvr;
	NocgenNode* m_sysinfo;
	
	//Net name for CCLK pin, if used
	std::string m_cclknet;
	
	//Target dependencies
	std::vector<std::string> m_dtargets;
	
	//Floorplan constraints applied after router generation
	//(so we can floorplan routers, namesrvr, etc)
	std::map< std::string, std::vector<std::string> > m_latefloorplans;
	
	//HMAC key for the name server (512 bits)
	unsigned char m_namesrvrKey[64];
	
	//The reference clock used for calibrating I/O delays
	std::string m_iodelayRefclk;
};

#endif

